"""
进度 | 业务层
"""

import utils.enum_utils as enum
from biz.base_biz import (
    CreatorBase,
    GetterBase,
    UpdatorBase,
    ValidatorBase,
)
from components.global_param import get_user_id
from mapping import ProcessMapping
from models.po import ProcessPO
from models.request import (
    ProcessDetailRequest,
    ProcessListRequest,
    ProcessTerminateRequest,
)
from models.vo import ProcessDetailVO
from my_typing import *
from service import ProcessService
from utils.data_utils.special import ObjectIdStr
from utils.exception_utils import BusinessError
from utils.mock_utils import DATETIME


class Model:
    """ 模型信息 """

    ID_FIELD: str = "process_id"
    NAME: str = "进度"
    PO = ProcessPO
    SERVICE = ProcessService


class ProcessValidator(ValidatorBase):
    """ 进度 | 校验器 """

    model_id_field = Model.ID_FIELD
    model_name = Model.NAME
    model_po = Model.PO
    model_service = Model.SERVICE

    BAN_OP_STATUS: list[enum.ProcessStatus] = [
        enum.ProcessStatus.TERMINATED,
        enum.ProcessStatus.EXCEPTION,
        enum.ProcessStatus.FINISHED,
    ]
    """ 禁止继续操作的状态 """

    # -------------------- validate_xxx --------------------

    @classmethod
    def validate_can_be_terminate(cls, process_id: ObjectIdStr) -> None:
        """ 校验进度是否可以被终止 """

        if (
            (process_po := ProcessService.get_one_by_id(process_id))
            and enum.ProcessStatus.is_ban_op_status(process_po.status)
        ):
            raise BusinessError(f"进度 ID <{str(process_id)}> {process_po.status.label}，无法终止")

    @classmethod
    def validate_detail(cls, request: ProcessDetailRequest) -> None:
        """
        校验 | 详情

            1. 进度是否存在
            2. 进度是否属于当前用户
        """

        cls.validate_union(
            {
                "id": request.process_id,
                "process_id": request.process_id,
                "user_id": get_user_id(),
            },
            cls.validate_exist,
            cls.validate_mine,
        )

    @classmethod
    def validate_terminate(cls, request: ProcessTerminateRequest) -> None:
        """
        校验 | 终止

            1. 进度是否存在
            2. 进度是否属于当前用户
            3. 进度是否可以被终止
        """

        cls.validate_union(
            {
                "id": request.process_id,
                "process_id": request.process_id,
                "user_id": get_user_id(),
            },
            cls.validate_exist,
            cls.validate_mine,
            cls.validate_can_be_terminate,
        )


class ProcessGetter(GetterBase):
    """ 进度 | 获取器 """

    model_mapping = ProcessMapping
    model_validator = ProcessValidator

    @classmethod
    def get_list_query(cls, request: ProcessListRequest) -> dict:
        condition = cls.Condition({"user_id": get_user_id()})

        condition.add_eq("task", value=request.task)
        condition.add_eq("status", value=request.status)

        return condition.get_query()


class ProcessHandler:
    """ 进度 | 处理器 """

    @staticmethod
    def init_process(task: enum.ProcessTask) -> ProcessPO:
        """ 初始化进度对象 """

        if not task:
            raise ValueError("task 不能为空")

        process_po = ProcessPO(
            user_id=get_user_id(),
            task=task,
        )
        ProcessService.insert_one_with_history(process_po)
        CreatorBase.version_log(process_po)

        return process_po

    @staticmethod
    def get_process_for_update(process_id: ObjectIdStr) -> ProcessPO:
        """
        获取进度对象

        Raises:
            ValueError 1: 请传入 process_id
            ValueError 2: 进度 ID <XXX> 已终止，无法继续操作
            ValueError 3: 进度 ID <XXX> 发生异常，无法继续操作
            ValueError 4: 进度 ID <XXX> 已完成，无法继续操作
            ValueError 5: 进度 ID <XXX> 已不存在
        """

        if not process_id:
            raise ValueError("请传入 process_id")

        process_po: ProcessPO | None = ProcessService.get_one_by_id(process_id)

        if not process_po:
            raise ValueError(f"进度 ID <{str(process_id)}> 不存在")

        if enum.ProcessStatus.is_ban_op_status(process_po.status):
            raise ValueError(f"进度 ID <{str(process_id)}> {process_po.status.label}，无法继续操作")

        return process_po

    @classmethod
    def update_process(
        cls,
        process_id: ObjectIdStr,
        percent: float,
    ) -> None:
        """ 更新进度对象 """

        percent = int(percent)

        if percent < 0:
            raise ValueError("percent 不能小于 0")

        if percent > 100:
            percent = 100

        process_po: ProcessPO = cls.get_process_for_update(process_id)

        if percent <= process_po.percent:
            raise ValueError("percent 不能小于等于当前进度")

        process_po.percent = percent
        ProcessService.update_one_with_history(process_po)

    @classmethod
    def finish_process(
        cls,
        process_id: ObjectIdStr,
        result: dict,
    ) -> None:
        """ 完成进度对象 """

        old_process_po: ProcessPO = cls.get_process_for_update(process_id)
        new_process_po: ProcessPO = old_process_po.model_copy(deep=True)
        new_process_po.status = enum.ProcessStatus.FINISHED
        new_process_po.percent = 100
        new_process_po.result = {
            **result,
            "use_time": (DATETIME.now() - new_process_po.create_time).total_seconds(),
        }
        ProcessService.update_one_with_history(new_process_po)
        UpdatorBase.version_log(
            old_process_po,
            new_process_po,
            model_operation=enum.ModelOperation.TERMINATE,
        )

    @staticmethod
    def exception_process(
        process_po: ProcessPO,
        exception_msg: str,
        result: DictOrNone = None,
    ) -> None:
        """ 异常进度对象 """

        if len(exception_msg) > 1024:
            exception_msg = exception_msg[:1021] + "..."

        old_process_po: ProcessPO = process_po
        new_process_po: ProcessPO = old_process_po.model_copy(deep=True)

        new_process_po.status = enum.ProcessStatus.EXCEPTION
        new_process_po.exception_msg = exception_msg
        new_process_po.result = result or {}
        ProcessService.update_one_with_history(new_process_po)
        UpdatorBase.version_log(
            old_process_po,
            new_process_po,
            model_operation=enum.ModelOperation.TERMINATE,
        )


class ProcessTerminateHandler(UpdatorBase):
    """ 进度 | 终止 | 处理器 """

    @classmethod
    def _update_data(cls, request: ProcessTerminateRequest) -> ProcessPO:
        """ 更新数据 """

        old_process_po: ProcessPO = ProcessService.get_one_by_id(request.process_id)
        new_process_po: ProcessPO = old_process_po.model_copy(deep=True)
        new_process_po.status = enum.ProcessStatus.TERMINATED
        ProcessService.update_one(new_process_po)
        cls.version_log(
            old_process_po,
            new_process_po,
            model_operation=enum.ModelOperation.TERMINATE
        )

        return new_process_po

    @classmethod
    def terminate(cls, request: ProcessTerminateRequest) -> ProcessDetailVO:
        """ 终止进度 """

        ProcessValidator.validate_terminate(request)
        process_po: ProcessPO = cls._update_data(request)
        vo: ProcessDetailVO = ProcessMapping.po_2_detail_vo(process_po)

        return vo
